
#include "apdu_lib_ecc_mgr.h"
#include "apdu_lib_common.h"

#include "../apdu.core/apdu.h"

#include "../../mk_lib/mk_auto_ptr.h"
#include "../../mk_lib/mk_utility.h"

#include <stdlib.h>
#include <string.h>
#include "../apdu.algo/mac.h"

extern int	g_sw;

int app_gen_ecc_keypair(HANDLE devHandle, int app_id, int container_id, int bits,
						unsigned char * pub_key_blob, int *key_blob_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_ecc_keypair(app_id, container_id, bits);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*key_blob_len < data_len)
	{
		return 3;
	}

	*key_blob_len = data_len;
	memcpy(pub_key_blob, data, data_len);

	return 0;

}

int app_import_ecc_keypair( HANDLE devHandle, int app_id, int container_id, unsigned char * enveloped_key_blob, int key_blob_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_import_ecc_keypair(app_id, container_id, enveloped_key_blob, key_blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_ecc_sign_data( HANDLE devHandle,int app_id, int container_id, int input_mode, 
					  unsigned char * user_id, int id_len, unsigned char * input_data, int input_len,
					  unsigned char * signature, int * sig_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_sign_data(app_id, container_id, input_mode, 
					user_id, id_len, input_data, input_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if( * sig_len < data_len)
	{
		return 3;
	}
	
	*sig_len = data_len;
	memcpy(signature, data, data_len);

	return 0;
}

int app_ecc_sign_data_ex( HANDLE devHandle,int app_id, int container_id, int input_mode,int key_spec,
						 unsigned char * user_id, int id_len,
						 unsigned char * input_data, int input_len,
						 unsigned char * signature, int * sig_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_sign_data_ex(app_id, container_id, input_mode, key_spec,
		user_id, id_len, input_data, input_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if( * sig_len < data_len)
	{
		return 3;
	}

	*sig_len = data_len;
	memcpy(signature, data, data_len);

	return 0;
}


int app_ecc_verify( HANDLE devHandle,unsigned char * ecc_pub_key_blob, int key_blob_len, 
				   unsigned char * input_data, unsigned long input_len,
				   unsigned char * ecc_signature_blob, int sig_blob_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_verify(ecc_pub_key_blob, key_blob_len, input_data,
			input_len, ecc_signature_blob, sig_blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_ecc_export_session_key( HANDLE devHandle, int app_id, int container_id, unsigned long alg_id,
							   unsigned char * ecc_pub_key_blob, unsigned long key_blob_len,
							   unsigned char * encipher_blob, int * encipher_blob_len, 
							   int * session_key_id)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_export_session_key(app_id, container_id, alg_id, 
							ecc_pub_key_blob, key_blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*encipher_blob_len  + 2 < data_len)
	{
		return 3;
	}

	*encipher_blob_len = data_len - 2;

	memcpy(encipher_blob, data, *encipher_blob_len);
	memcpy(session_key_id, data + data_len - 2, 2);
	mk_utility::reverse_bytes(session_key_id, 2);

	return 0;
}

int app_ecc_export_session_key_ex( HANDLE devHandle,int app_id, int container_id, int session_key_id,
								  unsigned char * ecc_pub_key_blob, unsigned long key_blob_len,
								  unsigned char * encipher_blob, int *encipher_blob_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_export_session_key_ex(app_id, container_id, session_key_id, 
							ecc_pub_key_blob, key_blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*encipher_blob_len < data_len)
	{
		return 3;
	}
	
	*encipher_blob_len = data_len;

	memcpy(encipher_blob, data, data_len);
	return 0;
}

int app_ecc_export_session_key2( HANDLE devHandle,int app_id, int container_id, int session_key_id,
								  unsigned char * ecc_pub_key_blob, unsigned long key_blob_len,
								  unsigned char * encipher_blob, int *encipher_blob_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_export_session_key2(app_id, container_id, session_key_id, 
		ecc_pub_key_blob, key_blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*encipher_blob_len < data_len)
	{
		return 3;
	}

	*encipher_blob_len = data_len;

	memcpy(encipher_blob, data, data_len);
	return 0;
}


int app_ext_ecc_encrypt( HANDLE devHandle,unsigned char * ecc_pub_key_blob, unsigned long key_blob_len, 
						unsigned char * input_data, unsigned long input_len, 
						unsigned char * encipher_blob, int * encipher_blob_len )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ext_ecc_encrypt(ecc_pub_key_blob, key_blob_len, input_data, input_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*encipher_blob_len < data_len)
	{
		return 3;
	}

	*encipher_blob_len = data_len;

	memcpy(encipher_blob, data, data_len);
	return 0;
}

int app_gen_agreement_data_with_ecc( HANDLE devHandle,int app_id, int container_id, UINT32 alg_id,
									unsigned char * user_id, int id_len,
									unsigned char * tmp_ecc_pub_key_blob, 
									UINT32 key_blob_len, UINT32 *agreement_handle )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_agreement_data_with_ecc(app_id, container_id, alg_id, user_id, id_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(key_blob_len < data_len + 4)
	{
		return 3;
	}

	memcpy(tmp_ecc_pub_key_blob, data, data_len-4);
	memcpy(agreement_handle, data + data_len - 4, 4);
	mk_utility::reverse_bytes(agreement_handle, 4);

	return 0;
}

int app_gen_agreement_data_and_key_with_ecc( HANDLE devHandle,int app_id, int container_id, unsigned long alg_id,
											unsigned char * sponsor_pub_key_blob, unsigned long sponsor_key_blob_len, 
											unsigned char * sponsor_tmp_pub_key_blob, unsigned long sponsor_tmp_key_blob_len,
											unsigned char * sponsor_id, int sponsor_id_len, 
											unsigned char * responser_id, int responser_id_len,
											unsigned char * responser_tmp_pub_key_blob, unsigned int *responser_tmp_key_blob_len, 
											int * session_key_id )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_agreement_data_and_key_with_ecc(app_id, container_id, alg_id, 
						sponsor_pub_key_blob, sponsor_key_blob_len, sponsor_tmp_pub_key_blob, sponsor_tmp_key_blob_len,
						sponsor_id, sponsor_id_len, responser_id,responser_id_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*responser_tmp_key_blob_len < data_len - 4)
	{
		return 3;
	}

	*responser_tmp_key_blob_len = data_len - 4;

	memcpy(responser_tmp_pub_key_blob, data, data_len-4);
	memcpy(session_key_id, data + data_len-4, 4);
	mk_utility::reverse_bytes(session_key_id, 4);
	return 0;
}

int app_gen_agreement_data_and_key_with_ecc_ex( HANDLE devHandle,int app_id, int container_id, 
											int key_spec, unsigned long alg_id,
											unsigned char * sponsor_pub_key_blob, unsigned long sponsor_key_blob_len, 
											unsigned char * sponsor_tmp_pub_key_blob, unsigned long sponsor_tmp_key_blob_len,
											unsigned char * sponsor_id, int sponsor_id_len, 
											unsigned char * responser_id, int responser_id_len,
											unsigned char * responser_tmp_pub_key_blob, unsigned int *responser_tmp_key_blob_len, 
											int * session_key_id )
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_agreement_data_and_key_with_ecc_ex(app_id, container_id, key_spec, alg_id, 
		sponsor_pub_key_blob, sponsor_key_blob_len, sponsor_tmp_pub_key_blob, sponsor_tmp_key_blob_len,
		sponsor_id, sponsor_id_len, responser_id,responser_id_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*responser_tmp_key_blob_len < data_len - 4)
	{
		return 3;
	}

	*responser_tmp_key_blob_len = data_len - 4;

	memcpy(responser_tmp_pub_key_blob, data, data_len-4);
	memcpy(session_key_id, data + data_len-4, 4);
	mk_utility::reverse_bytes(session_key_id, 4);
	return 0;
}


int app_gen_key_with_ecc( HANDLE devHandle,int app_id, int container_id,
						 unsigned long agreement_handle, unsigned char * pub_key_blob,
						 unsigned long key_blob_len, unsigned char * tmp_key_blob,
						 unsigned long tmp_key_blob_len, unsigned char * responser_id, int responser_id_len,
						 int * session_key_id)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_key_with_ecc(app_id, container_id, agreement_handle, 
						pub_key_blob, key_blob_len, tmp_key_blob, tmp_key_blob_len, responser_id, responser_id_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(data_len < 4)
	{
		return 3;
	}

 	memcpy(session_key_id, data, 4);
	mk_utility::reverse_bytes(session_key_id, 4);
	return 0;
}


int app_gen_key_with_ecc_ex( HANDLE devHandle,int app_id, int container_id, int key_spec,
						 unsigned long agreement_handle, unsigned char * pub_key_blob,
						 unsigned long key_blob_len, unsigned char * tmp_key_blob,
						 unsigned long tmp_key_blob_len, unsigned char * responser_id, int responser_id_len,
						 int * session_key_id)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_key_with_ecc_ex(app_id, container_id, key_spec, agreement_handle, 
		pub_key_blob, key_blob_len, tmp_key_blob, tmp_key_blob_len, responser_id, responser_id_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(data_len < 4)
	{
		return 3;
	}

	memcpy(session_key_id, data, 4);
	mk_utility::reverse_bytes(session_key_id, 4);
	return 0;
}

int	app_ecc_private_decrypt(HANDLE devHandle, int app_id, int container_id, int key_spec,
							unsigned char * input_data, unsigned long input_len,
							unsigned char * plain, int *plain_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_private_decrypt(app_id, container_id, key_spec, 
							input_data, input_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*plain_len < data_len)
	{
		return 3;
	}

	*plain_len = data_len;
	memcpy(plain, data, data_len);
	return 0;
}

int app_import_ext_ecc_keypair(HANDLE devHandle, int app_id, int container_id, int key_spec,
							   unsigned char * ecc_key_blob, int key_blob_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_import_ext_ecc_keypair(app_id, container_id, key_spec, ecc_key_blob, key_blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_gen_ext_ecc_keypair(HANDLE devHandle, unsigned char * prikey_blob, int * blob_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_gen_ext_ecc_keypair();

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*blob_len < data_len)
	{
		return 3;
	}

	*blob_len = data_len;
	memcpy(prikey_blob, data, data_len);

	return 0;
}

int app_export_ext_ecc_pubkey(HANDLE devHandle, unsigned char * pubkey_blob, int * blob_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_export_ext_ecc_pub_key();

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*blob_len < data_len)
	{
		return 3;
	}

	*blob_len = data_len;
	memcpy(pubkey_blob, data, data_len);

	return 0;
}

int app_import_ecc_keypair_to_ram(HANDLE devHandle, unsigned char * ecc_keypair_blob, int blob_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_import_ext_ecc_keypair_to_ram(ecc_keypair_blob, blob_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

int app_ram_ecc_sign(HANDLE devHandle, unsigned char * input, int len,
						unsigned char * signature_data, int * siganature_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ram_ecc_operation(0, input, len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*siganature_len < data_len)
	{
		return 3;
	}

	*siganature_len = data_len;
	memcpy(signature_data, data, data_len);

	return 0;
}

int app_ram_ecc_decrypt(HANDLE devHandle, unsigned char * cipher_data, int cipher_len,
						unsigned char * plain_data, int * plain_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ram_ecc_operation(1, cipher_data, cipher_len);

		mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if(*plain_len < data_len)
	{
		return 3;
	}

	*plain_len = data_len;
	memcpy(plain_data, data, data_len);

	return 0;
}

int app_ecc_sign_data_interactive( HANDLE devHandle,int app_id, int container_id,
								  int input_mode, int key_spec, int timeout,
								  unsigned char * user_id, int id_len,
								  unsigned char * input_data, int input_len,
								  unsigned char * signature, int * sig_len)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_sign_data_interactive(app_id, container_id, input_mode, key_spec,timeout,
							user_id, id_len, input_data, input_len);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	int data_len = 0;
	unsigned char * data = newApdu->get_response_data(&data_len);
	if( * sig_len < data_len)
	{
		return 3;
	}

	*sig_len = data_len;
	memcpy(signature, data, data_len);

	return 0;
}

int app_ecc_sign_data_interactive_cancel( HANDLE devHandle,int app_id, int container_id, int input_mode, int key_spec)
{
	apdu * newApdu  =  NULL;
	newApdu = get_ecc_mgr()->create_apdu_ecc_sign_data_interactive_cancel(app_id, container_id, input_mode, key_spec);

	mk_auto_ptr<apdu> ap(newApdu);

	if( 0 != get_dev_mgr()->transmit_apdu(devHandle,newApdu, &g_sw))
	{
		return 1;
	}

	if(g_sw != 0x9000)
	{
		return 2;
	}

	return 0;
}

